package com.autumn.workflow.service;

import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;

import com.autumn.workflow.command.ParamCommand;
import com.autumn.workflow.model.ProcessTrace;
import com.autumn.workflow.model.UserTaskNode;

public interface WorkflowService {

    //======命令执行API=========
    //////////////////////////
    /**
     * 执行Activiti原生的命令对象
     * 
     * @param command
     * @return
     */
    <T> T execute(Command<T> command);

    /**
     * 执行需传递执行参数的命令
     * 
     * @param command 需传递执行参数的命令对象
     * @param param 参数
     * @return
     */
    <P, T> T execute(ParamCommand<P, T> command, P param);

    /**
     * 执行需传递执行参数的命令
     * 
     * @param commandClass 命令实现类的类型，必须在Spring容器中注册
     * @param param 参数
     * @return
     */
    <P, T> T execute(Class<? extends ParamCommand<P, T>> commandClass, P param);

    /**
     * 执行需传递执行参数的命令
     * 
     * @param commandBeanname 命令实现类注册在Spring容器中的Beanname
     * @param param 参数
     * @return
     */
    <P, T> T execute(String commandBeanname, P param);

    //======流程定义API=========
    //////////////////////////
    /**
     * 发布流程定义
     * 
     * @param classpathResource 类路径下bpmn文件名
     * @param userId 发布人员ID
     */
    Deployment deployProcessDefinition(String classpathResource, String userId);

    /**
     * 发布流程定义
     * 
     * @param zipInputStream 流程定义归档文件的流
     * @param userId 发布人员ID
     */
    Deployment deployProcessDefinition(ZipInputStream zipInputStream, String userId);

    /**
     * 发布流程定义
     * 
     * @param resourceName 资源名称
     * @param inputStream 流程定义输入流
     * @param userId 发布人员ID
     */
    Deployment deployProcessDefinition(String resourceName, InputStream inputStream, String userId);

    /**
     * 发布流程定义
     * 
     * @param resourceName 资源名称
     * @param bytes 流程定义字节数组
     * @param userId 发布人员ID
     */
    Deployment deployProcessDefinition(String resourceName, byte[] bytes, String userId);

    /**
     * 根据流程定义ID初始化流程任务和流程路径
     * 
     * @param procDefId 流程定义Id
     */
    void initializeUserTaskNodeAndFlow(String procDefId);

    /**
     * 根据流程定义Key查询流程定义（最后一个版本）
     * 
     * @param procDefKey 流程定义Key
     * @return
     */
    ProcessDefinition queryProcessDefinition(String procDefKey);

    //======流程实例API=========
    //////////////////////////
    /**
     * 启动流程实例，根据流程定义KEY启动该流程定义最新版本的流程实例
     * 
     * @param procDefKey 流程定义的key
     * @param businessKey 绑定业务主键
     * @param startUserId 流程发起人ID
     */
    ProcessInstance startProcessInstanceByKey(String procDefKey, String businessKey, String startUserId);

    /**
     * 启动流程实例，根据流程定义KEY启动该流程定义最新版本的流程实例
     * 
     * @param procDefKey 流程定义的key
     * @param variables 流程变量，这些变量和流程实例绑定（每个实例保存这些变量的副本，流程实例启动后，参数变化，也不影响这些变量）
     * @param businessKey 绑定业务主键
     * @param startUserId 流程发起人ID
     */
    ProcessInstance startProcessInstanceByKey(String procDefKey, Map<String, Object> variables, String businessKey, String startUserId);

    /**
     * 启动流程实例，根据流程定义ID启动流程实例，可以使用该方法启动历史流程定义的实例
     * 
     * @param procDefId 流程定义ID
     * @param businessKey 绑定业务主键
     * @param startUserId 流程发起人ID
     */
    ProcessInstance startProcessInstanceById(String procDefId, String businessKey, String startUserId);

    /**
     * 启动流程实例，根据流程定义ID启动流程实例，可以使用该方法启动历史流程定义的实例
     * 
     * @param procDefId 流程定义ID
     * @param variables 流程变量，这些变量和流程实例绑定（每个实例保存这些变量的副本，流程实例启动后，参数变化，也不影响这些变量）
     * @param businessKey 绑定业务主键
     * @param startUserId 流程发起人ID
     */
    ProcessInstance startProcessInstanceById(String procDefId, Map<String, Object> variables, String businessKey, String startUserId);

    /**
     * 查询流程实例绑定的变量，在推进流程时，有时候需要根据流程发起时的变量确定下一步流程怎么走，这个时候可以调用该方法先获取绑定的变量
     * 
     * @param procInstId 流程实例ID
     * @return
     */
    Map<String, Object> queryProcessInstanceVariables(String procInstId);

    /**
     * 查询当前活动节点，如果有多个活动节点，抛出异常
     * 
     * @param procInstId
     * @return
     */
    String queryCurrentNodeId(String procInstId);

    /**
     * 查询当前活动节点列表
     * 
     * @param procInstId
     * @return
     */
    List<String> queryCurrentNodeIds(String procInstId);

    /**
     * 流程是否结束
     * 
     * @param procInstId
     * @return
     */
    boolean isEnd(String procInstId);

    //======流程任务API=========
    //////////////////////////
    /**
     * 领取任务，该接口会检查当前任务是否已经被其他人领取
     * 
     * @param taskId 任务ID
     * @param userId 任务领取人ID
     */
    void claimByTaskId(String taskId, String userId);

    /**
     * 放弃任务
     * 
     * @param taskId 任务ID
     */
    void unclaimByTaskId(String taskId);

    /**
     * 修改任务领取人，该接口不会检查当前任务是否已经被其他人领取，直接修改责任人
     * 
     * @param taskId 任务ID
     * @param userId 新的任务领取人
     */
    void changeAssigneeByTaskId(String taskId, String userId);

    /**
     * 查询所有可能的下一任务节点，可参看ACT_TASK_NODE、ACT_TASK_FLOW表
     * 
     * @param procDefId 流程定义Id
     * @param srcTaskKey 当前任务节点
     * @param action 操作类型（1前进、0回退等）
     * @return
     */
    List<UserTaskNode> queryNextPossibleUserTaskNodes(String procDefId, String srcTaskKey, int action);

    /**
     * 正常流程完成任务，会检查当前任务责任人是否为userId，如果不是抛出异常
     * 
     * @param taskId 任务ID
     * @param userId 任务处理人ID
     */
    void completeByTaskId(String taskId, String userId);

    /**
     * 正常流程完成任务，会检查当前任务责任人是否为userId，如果不是抛出异常
     * 
     * @param taskId 任务ID
     * @param userId 任务处理人ID
     * @param remark 任务备注
     */
    void completeByTaskId(String taskId, String userId, String remark);

    /**
     * 正常流程完成任务，会检查当前任务责任人是否为userId，如果不是抛出异常
     * 
     * @param taskId 任务ID
     * @param action 流程任务的跳转变量，在调用该方法之前，先计算好action的值
     * @param userId 任务处理人ID
     */
    void completeByTaskId(String taskId, int action, String userId);

    /**
     * 正常流程完成任务，会检查当前任务责任人是否为userId，如果不是抛出异常
     * 
     * @param taskId 任务ID
     * @param action 流程任务的跳转变量，在调用该方法之前，先计算好action的值
     * @param userId 任务处理人ID
     * @param remark 任务备注
     */
    void completeByTaskId(String taskId, int action, String userId, String remark);

    /**
     * 正常流程完成任务，会检查当前任务责任人是否为userId，如果不是抛出异常
     * 
     * @param taskId 任务ID
     * @param variables 可以控制执行路径的变量
     * @param userId 任务处理人ID
     */
    void completeByTaskId(String taskId, Map<String, Object> variables, String userId);

    /**
     * 正常流程完成任务，会检查当前任务责任人是否为userId，如果不是抛出异常
     * 
     * @param taskId 任务ID
     * @param variables 可以控制执行路径的变量
     * @param userId 任务处理人ID
     * @param remark 任务备注
     */
    void completeByTaskId(String taskId, Map<String, Object> variables, String userId, String remark);

    /**
     * 自由流程（由调用者自己选择下一任务节点）完成任务，会检查当前任务责任人是否为userId，如果不是抛出异常
     * 
     * @param taskId 任务ID
     * @param action 操作类型（1前进、0回退等）
     * @param userId 任务处理人ID
     * @param destTaskKey 目标节点
     */
    void completeFreedomByTaskId(String taskId, int action, String userId, String destTaskKey);

    /**
     * 自由流程（由调用者自己选择下一任务节点）完成任务，会检查当前任务责任人是否为userId，如果不是抛出异常
     * 
     * @param taskId 任务ID
     * @param action 操作类型（1前进、0回退等）
     * @param userId 任务处理人ID
     * @param destTaskKey 目标节点
     * @param remark 任务备注
     */
    void completeFreedomByTaskId(String taskId, int action, String userId, String destTaskKey, String remark);

    //======流程图API=========
    //////////////////////////
    /**
     * 根据流程定义的Key获取流程资源（静态流程图）
     * 
     * @param procDefKey 流程定义Key
     * @return byte[]
     */
    byte[] loadResourceByProcDefKey(String procDefKey);

    /**
     * 根据流程定义获取流程资源（静态流程图）
     * 
     * @param procDefId 流程定义ID
     * @return byte[]
     */
    byte[] loadResourceByProcDefId(String procDefId);

    /**
     * 根据流程实例ID获取流程资源（动态流程图）
     * 
     * @param procInstId 流程实例ID
     * @return byte[]
     */
    byte[] loadResourceByProcInstId(String procInstId);

    /**
     * 加载流程跟踪信息
     * 
     * @param procInstId
     * @return
     */
    ProcessTrace loadProcessTrace(String procInstId);
}
